#ifndef _CMDLINE_CMDLINE_H_
#define _CMDLINE_CMDLINE_H_

#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
#include <string>

#include "cmdline_exceptions.h"
#include "../util/wstr.h"

namespace cmdline {

// Commandline option
struct Option {
	Option(wchar_t charflag, std::wstring strflag, bool params, std::wstring description) :
		charflag(charflag), strflag(strflag), params(params), description(description) {}
	wchar_t charflag;
	std::wstring strflag;
	std::wstring description;
	bool params;
};

// Commandline option's value
struct Parameter {
	Parameter(Option *option) : option(option) {}
	Option *option;
	std::wstring wstr;
	std::string str;
};

class CommandlineParser {
public:
	CommandlineParser();
	~CommandlineParser();

	//// Getting ready to parsing ////

	// Add a flag to be parsed. -charflag, --strflags, params is true
	// if needs to be followed by a param, description is for help.
	// If charflag is L'-', it is disabled.
	void addOption(wchar_t charflag, std::wstring strflag, bool params,
		std::wstring description);
	
	// Allow additional parameters, e.g. parameter with no flags before them.
	// -1 for unlimited, 0 for none, positive for some limit.
	void setMaxUnnamedParams(int max);


	//// Parsing ////

	// Parse commandline flags. This may throw CmdlineException.
	void parse(int argc, char *argv[]);


	//// Results ////

	// Get the named parameters with this.
	std::vector<Parameter*> &getParams();

	// Ask the unnamed wchar parameters with this.
	std::vector<std::wstring> &getUnnamedParams_wstr();
	// Ask the unnamed char parameters with this.
	std::vector<std::string> &getUnnamedParams_str();


	//// Help ////
	
	// Get help string
	std::wstring help();

private:
	bool isSingleCharacterFlag(std::wstring param);
	std::vector<wchar_t> getSingleCharacterFlags(std::wstring param);

	bool isMultiCharacterFlag(std::wstring param);
	std::wstring getMultiCharacterFlag(std::wstring param);

	Option *findOption(wchar_t charflag);
	Option *findOption(std::wstring strflag);

	int max_unnamed_params;
	std::vector<std::wstring> unnamedparams_wstr;
	std::vector<std::string> unnamedparams_str;

	std::vector<std::wstring> params_wstr;
	std::vector<std::string> params_str;

	std::vector<Option*> options;
	std::vector<Parameter*> parameters;
};

}

#endif
